/*
 * Copyright (C) 2024, KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * Authors: hxf <hewenfei@kylinos.cn>
 *
 */

import QtQuick 2.15
import QtQml.Models 2.12
import QtQuick.Layouts 1.12

import org.ukui.menu.core 1.0
import org.ukui.menu.extension 1.0
import "../extensions" as Extension
import AppControls2 1.0 as AppControls2

import org.ukui.quick.items 1.0 as UkuiItems
import org.ukui.quick.platform 1.0 as Platform

ListView {
    id: root
    signal openFolderSignal(string folderId, string folderName, int x, int y)
    signal contentShowFinished()
    property bool isContentShow
    property bool isSearching

    property int itemHeight: 40
    property alias sourceModel: appGroupModel.sourceModel
    property int cellWidth: 180
    property int cellHeight: 180
    property int column: Math.floor(width / cellWidth)

    property var currentGridView: null
    property int currentNum: -2
    property string currentId: ""

    spacing: 5
    clip: true
    boundsBehavior: Flickable.StopAtBounds
    currentIndex: -1
    highlightMoveDuration: 0

    //除header外其他鼠标区域，用于关闭编辑模式或隐藏全屏开始菜单，当鼠标进入appItem和编辑按钮时失效
    MouseArea {
        id: appArea
        anchors.fill: headerItem.parent
        onClicked: {
            if (mainWindow.editMode) {
                mainWindow.editMode = false;
            } else {
                mainWindow.hide();
            }
        }
    }

    onFocusChanged: {
        if (focus) {
            if (root.isSearching) {
                currentIndex = 0;
                itemAtIndex(0).forceActiveFocus();
            } else {
                headerItem.forceActiveFocus();
            }
        } else {
            currentIndex = -1;
            currentGridView.focus = false
            currentGridView = null;
            currentNum = -2;
        }
    }
    Keys.onPressed: {
        if (!currentGridView || currentGridView.itemCurrentIndex === -1) return;

        var newIndex = currentGridView.itemCurrentIndex;
        var row = Math.floor(newIndex / root.column);
        var col = newIndex % root.column;

        switch (event.key) {
        case Qt.Key_Up:
            row = row - 1;
            break;
        case Qt.Key_Down:
            row = row + 1;
            break;
        case Qt.Key_Left:
            col = Math.max(0, col - 1);
            break;
        case Qt.Key_Right:
            col = Math.min(root.column - 1, col + 1);
            break;
        case Qt.Key_Enter:
            appManager.launchApp(currentId);
            event.accepted = true;
            return;
        case Qt.Key_Return:
            appManager.launchApp(currentId);
            event.accepted = true;
            return;
        default:
            return;
        }

        newIndex = row * root.column + col;
        if (row < 0 || newIndex >= currentGridView.itemCount) {
            if (currentNum === 0 && newIndex < 0) {
                if (!root.isSearching) headerItem.forceActiveFocus();
            } else if (currentNum === -1 && newIndex >= currentGridView.itemCount) {
                currentIndex = 0;
                itemAtIndex(0).forceActiveFocus();
            }
            event.accepted = false;
        } else {
            currentGridView.itemCurrentIndex = newIndex;
            event.accepted = true;
        }
    }

    model: AppGroupModel {
        id: appGroupModel
    }

    delegate: Item {
        id: groupItem
        property int itemCount: appGridView.count
        property int itemCurrentIndex: -1
        width: ListView.view.width
        height: childrenRect.height

        onFocusChanged: {
            if (focus) {
                root.currentGridView = this;
                itemCurrentIndex = 0;
                currentNum = index;
            } else {
                itemCurrentIndex = -1;
            }
        }

        Column {
            width: parent.width
            height: childrenRect.height
            spacing: 0

            AppControls2.LabelItem {
                width: parent.width
                height: root.itemHeight
                displayName: model.name === "" ? qsTr("All Applications") : model.name
                visible: displayName !== ""
                onEntered: appArea.enabled = false
                onExited: appArea.enabled = true
            }

            GridView {
                id: appGridView
                property bool isFavorite: false
                anchors.horizontalCenter: parent.horizontalCenter
                width: root.cellWidth * root.column
                height: contentHeight
                cellWidth: root.cellWidth
                cellHeight: root.cellHeight
                interactive: false

                currentIndex: groupItem.itemCurrentIndex
                onCurrentItemChanged: {
                    if (!currentItem) return;
                    var itemYInListView = currentItem.y + root.y + groupItem.y;
                    var visibleTop = root.contentY;
                    var visibleBottom = visibleTop + root.height;

                    if (itemYInListView < visibleTop) {
                        var targetY = itemYInListView;
                        if (currentItem.y === 0) targetY -= root.itemHeight;
                        root.contentY = targetY;
                    } else if (itemYInListView + currentItem.height > visibleBottom) {
                        targetY = itemYInListView + currentItem.height - root.height;
                        root.contentY = targetY;
                    }
                }

                model: DelegateModel {
                    model: appGroupModel

                    Component.onCompleted: {
                        // Warning: rootIndex只需要设置一次，多次设置会导致对应关系错误，
                        // delegateModel使用persistedIndex保存rootIndex，会自动进行修正
                        rootIndex = modelIndex(index);
                    }

                    delegate: Item {
                        id: appBaseItem
                        width: GridView.view.cellWidth
                        height: GridView.view.cellHeight

                        Accessible.role: Accessible.Button
                        Accessible.description: "This is an app button on ukui-menu"
                        Accessible.name: model.name

                        focus: GridView.isCurrentItem
                        onFocusChanged: {
                            if (focus) {
                                root.currentId = id;
                            }
                        }

                        FullScreenAppItem {
                            id: appItem
                            anchors.fill: parent
                            anchors.margins: 12

                            acceptedButtons: Qt.LeftButton | Qt.RightButton

                            text.text: model.name
                            icon.source: model.icon
                            icon.proxy.appId: model.desktopName === undefined ? "" : model.desktopName
                            isRecentInstalled: model.recentInstall === undefined ? false : model.recentInstall

                            hasFocus: (appBaseItem.GridView.isCurrentItem && root.currentIndex !== -1) ? true : false

                            onClicked: (event) => {
                                console.log("ICON_CLICK!", "DESKTOPFILE:", id);
                                if (event.button === Qt.LeftButton) {
                                    // openApplication
                                    appManager.launchApp(id);
                                } else if (event.button === Qt.RightButton) {
                                    menuManager.showMenu(model.id, MenuInfo.FullScreen);
                                }
                            }
                            onEntered: appArea.enabled = false
                            onExited: appArea.enabled = true

                            drag.target: appItem
                            onPressed: {
                                fullScreenUI.focus = false;
                                grabToImage(function(result) {
                                    Drag.imageSource = result.url
                                })
                            }
                            Drag.supportedActions: Qt.CopyAction
                            Drag.dragType: Drag.Automatic
                            Drag.active: appItem.drag.active
                            Drag.hotSpot.x: width / 2
                            Drag.hotSpot.y: height / 2
                            Drag.mimeData: {
                                "source": "ukui-menu",
                                "url": "app://" + model.id,
                                "favorite": model.favorite > 0
                            }
                        }

                        // 收藏按钮
                        Extension.EditModeFlag {
                            isFavorited: model.favorite > 0
                            anchors.top: parent.top
                            anchors.topMargin: 10
                            anchors.right: parent.right
                            anchors.rightMargin: 28
                            onClicked: {
                                appManager.changeFavoriteState(id, !isFavorited);
                            }
                            onIsEnteredChanged: {
                                appArea.enabled = !isEntered;
                            }
                        }
                    }
                }
            }
        }
    }

    header: MouseArea {
        id: favoriteItem
        property bool show: (visualModel.count > 0) && (!root.isSearching)
        property int itemCount: favoriteView.count
        property int itemCurrentIndex: -1
        width: show ? root.width : 0
        height: show ? childrenRect.height : 0
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        visible: show

        property var widgets: []
        property var widgetInfos: []
        property int widgetCount: 1

        Component.onCompleted: {
            widgetInfos.push({label: "favorite", display: "non-starred-symbolic", type: WidgetMetadata.Widget});
            widgets.push("favorite");
        }

        onFocusChanged: {
            if (focus) {
                root.currentGridView = this;
                itemCurrentIndex = 0;
                currentNum = -1;
            } else {
                itemCurrentIndex = -1;
            }
        }

        onClicked: {
            if (mouse.button === Qt.RightButton) {
                menu.open();
            } else if (mouse.button === Qt.LeftButton) {
                if (mainWindow.editMode) {
                    mainWindow.editMode = false;
                } else {
                    mainWindow.hide();
                }
            }
        }

        UkuiItems.Menu {
            id: menu
            content: UkuiItems.MenuItem {
                text: qsTr("Editing mode")
                icon: "edit-symbolic"
                onClicked: mainWindow.editMode = true;
            }
        }

        Column {
            width: parent.width
            height: childrenRect.height + spacing
            spacing: root.spacing

            AppControls2.LabelItem {
                width: parent.width
                height: root.itemHeight
                displayName: qsTr("Favorite")
            }

            Item {
                width: parent.width
                height: favoriteView.height

                DropArea {
                    z: -10
                    anchors.fill: parent
                    property int addedIndex: -1
                    property string addedId: ""

                    function reset() {
                        addedId = "";
                        var nullIndex = favoriteView.indexAtNullItem();
                        if (nullIndex > -1 && nullIndex < favoriteView.count) {
                            favoriteView.viewModel.items.remove(nullIndex);
                        }
                    }

                    onEntered: {
                        if (drag.getDataAsString("folder") === "true" || drag.getDataAsString("favorite") === "false") {
                            // 从应用组内部拖拽 || 从左侧列表添加到收藏
                            // 已经触发从左侧拖动到收藏区域的事件，不需要再次添加空白item
                            let id = "";
                            if (drag.getDataAsString("url").startsWith("app://")) {
                                id = drag.getDataAsString("url").slice(6);
                            }
                            if (addedId === id || id === "") {
                                return;
                            }

                            addedId = id;
                            addedIndex = favoriteView.count;
                            visualModel.items.insert(addedIndex, {"id":"", "icon":"", "name": ""});

                        } else if (drag.getDataAsString("favorite") === "true") {
                            drag.accepted = false;
                        } else {
                            // 收藏插件内拖拽
                            favoriteView.dragTypeIsMerge = false;
                        }
                    }

                    onPositionChanged: {
                        if ((drag.getDataAsString("folder") === "true" || drag.getDataAsString("favorite") === "false") && addedIndex > -1) {
                            var dragIndex = favoriteView.indexAt(drag.x, drag.y);

                            if (dragIndex < 0) {
                                return;
                            }

                            visualModel.items.move(addedIndex, dragIndex);
                            addedIndex = dragIndex;
                        }
                    }

                    onDropped: {
                        // folder需要在favorite之前判断，因为应用组内的应用favorite都为true
                        if (drop.getDataAsString("folder") === "true") {
                            reset();
                            favoriteModel.addAppFromFolder(drop.getDataAsString("url").slice(6), addedIndex);
                            folderLoader.isFolderOpened = false;

                        } else if (drop.getDataAsString("favorite") === "false") {
                            reset();
                            favoriteModel.addAppToFavorites(drop.getDataAsString("url").slice(6), addedIndex);
                        }
                    }
                    onExited: reset()
                }

                GridView {
                    id: favoriteView
                    anchors.horizontalCenter: parent.horizontalCenter
                    width: root.cellWidth * root.column
                    height: contentHeight
                    property string mergeToAppId: ""
                    property bool isMergeToFolder: false
                    property bool dragTypeIsMerge: false
                    property int exchangedStartIndex: 0
                    property alias viewModel: visualModel

                    property bool isFavorite: true

                    cellWidth: root.cellWidth
                    cellHeight: root.cellHeight
                    interactive: false

                    currentIndex: favoriteItem.itemCurrentIndex

                    function indexAtNullItem() {
                        var nullItemIndex;
                        for (var i = 0; i < favoriteView.count; i ++) {
                            if (favoriteView.itemAtIndex(i).id === "") {
                                nullItemIndex = i;
                                return nullItemIndex;
                            }
                        }
                        return -1;
                    }

                    onCurrentItemChanged: {
                        if (!currentItem) return;
                        var itemYInListView = currentItem.y + root.y + favoriteItem.y;
                        var visibleTop = root.contentY;
                        var visibleBottom = visibleTop + root.height;

                        if (itemYInListView < visibleTop) {
                            var targetY = itemYInListView;
                            if (currentItem.y === 0) targetY -= root.itemHeight;
                            root.contentY = targetY;
                        } else if (itemYInListView + currentItem.height > visibleBottom) {
                            targetY = itemYInListView + currentItem.height - root.height;
                            root.contentY = targetY;
                        }
                    }

                    model: DelegateModel {
                        id: visualModel
                        model: favoriteModel
                        delegate: Item {
                            id: container
                            width: favoriteView.cellWidth
                            height: favoriteView.cellHeight
                            property var id: model.id
                            focus: GridView.isCurrentItem
                            onFocusChanged: {
                                if (focus) {
                                    root.currentId = id;
                                }
                            }
                            Extension.FavoriteDelegate {
                                anchors.fill: parent
                                anchors.margins: 12
                                isFullScreen: true

                                borderColor: Platform.GlobalTheme.highlightActive
                                border.width: (container.GridView.isCurrentItem && root.currentNum === -1) ? 2 : 0

                                visualIndex: container.DelegateModel.itemsIndex
                                delegateLayout.anchors.topMargin: 16
                                delegateLayout.anchors.bottomMargin: 16
                                delegateLayout.spacing: 8
                                mergePrompt.anchors.topMargin: 10
                                mergePrompt.width: width*0.675
    //                            mergePrompt.width: 108
                                mergePrompt.radius: 32

                                Component.onCompleted: contentShowFinished.connect(resetOpacity)
                                Component.onDestruction: contentShowFinished.disconnect(resetOpacity)
                            }

                            //编辑模式标志
                            Extension.EditModeFlag {
                                id: tag
                                isFavorited: true
                                anchors.top: parent.top
                                anchors.topMargin: 10
                                anchors.right: parent.right
                                anchors.rightMargin: 28
                                onClicked: {
                                    visualModel.model.removeAppFromFavorites(id);
                                }
                            }
                        }
                    }

                    displaced: Transition {
                        NumberAnimation { properties: "x,y"; easing.type: Easing.InOutQuad; duration: 200 }
                    }
                    remove: Transition {
                        NumberAnimation { properties: "opacity"; to: 0; easing.type: Easing.InOutQuad; duration: 200 }
                    }
                }
            }
        }
    }
}
